package lib

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/ClickHouse/clickhouse-go/v2"
	"log"
	"os"
)

type DatabaseConfig struct {
	Driver   string `json:"driver"`
	Host     string `json:"host"`
	Port     int    `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Dbname   string `json:"dbname"`
}

type TaskConfig struct {
	Name   string `json:"name"`
	Cron   string `json:"cron"`
	Script string `json:"script"`
}

type ClickhouseConfig struct {
	Host     string `json:"host"`
	Port     string `json:"port"`
	User     string `json:"user"`
	Password string `json:"password"`
	Dbname   string `json:"dbname"`
}

type Config struct {
	Databases  map[string]DatabaseConfig `json:"databases"`
	Tasks      []TaskConfig              `json:"tasks"`
	Clickhouse ClickhouseConfig          `json:"clickhouse"`
}

func GetConfig(dir string) (map[string]*sql.DB, *Config, clickhouse.Conn, error) {
	env := os.Getenv("APP_ENV")
	if env == "" {
		env = "development"
	}
	//env := "production"
	config, err := LoadConfig(dir + "config/" + env + ".json")
	if err != nil {
		log.Fatalf("Error loading config: %v", err)
	}

	dbConnections, connectErr := ConnectAllDatabases(config.Databases)
	if connectErr != nil {
		log.Fatalf("Error connecting to databases: %v", connectErr)
	}

	clickhouseConnection, _ := ConnectClickHouse(config.Clickhouse)

	return dbConnections, config, clickhouseConnection, nil
}

func LoadConfig(filename string) (*Config, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	var config Config
	err = json.Unmarshal(data, &config)
	return &config, err
}

func ConnectAllDatabases(databases map[string]DatabaseConfig) (map[string]*sql.DB, error) {
	connections := make(map[string]*sql.DB)
	for name, dbConfig := range databases {
		db, err := ConnectDatabase(dbConfig)
		if err != nil {
			return nil, fmt.Errorf("error connecting to %s: %v", name, err)
		}
		connections[name] = db
	}
	return connections, nil
}

func ConnectDatabase(dbConfig DatabaseConfig) (*sql.DB, error) {
	// 构建 DSN（数据源名称）字符串
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
		dbConfig.User,
		dbConfig.Password,
		dbConfig.Host,
		dbConfig.Port,
		dbConfig.Dbname,
	)
	// 连接到 MySQL 数据库
	return sql.Open("mysql", dsn)
}

func CloseAllDatabases(connections map[string]*sql.DB) {
	for _, db := range connections {
		err := db.Close()
		if err != nil {
			return
		}
	}
}

// ConnectClickHouse 连接
func ConnectClickHouse(config ClickhouseConfig) (clickhouse.Conn, error) {
	clickhouseConn, clickErr := clickhouse.Open(&clickhouse.Options{
		Addr: []string{config.Host + ":" + config.Port},
		Auth: clickhouse.Auth{
			Database: config.Dbname,
			Username: config.User,
			Password: config.Password,
		},
		Protocol: clickhouse.Native, // 或者 clickhouse.HTTP
	})
	if clickErr != nil {
		log.Fatalf("Failed to connect to ClickHouse: %v", clickErr)
	}

	return clickhouseConn, nil
}
